# voxelizer_core.py

"""
体素化核心模块。
使用射线投射法和BVH加速结构将网格模型体素化。
"""

import math
import numpy as np
import time

from .constants import EPSILON
from .bvh_tree import build_bvh, BVHNode # 从bvh_tree导入
from .ray_tracer_utils import traverse_bvh_and_get_intersections, ray_intersects_triangle # 导入修改后的ray_intersects_triangle

# 三角化函数保持在此模块
def triangulate_face(
    face_indices: list[int], 
    all_vertices: list[list[float]]
) -> list[tuple[np.ndarray, np.ndarray, np.ndarray]]:
    """将多边形面三角化。"""
    triangles_vertices_np: list[tuple[np.ndarray, np.ndarray, np.ndarray]] = []
    num_face_verts = len(face_indices)

    if num_face_verts < 3:
        return triangles_vertices_np
    try:
        # 确保顶点数据类型为float64以匹配NumPy操作
        v0_coords_np = np.array(all_vertices[face_indices[0]], dtype=np.float64)
    except IndexError:
        # 日志记录可以由更上层的调用者（如main.py中的process函数）处理
        # print(f"错误 (triangulate_face): 顶点索引 {face_indices[0]} 超出范围。")
        return [] 

    for i in range(1, num_face_verts - 1):
        try:
            v1_coords_np = np.array(all_vertices[face_indices[i]], dtype=np.float64)
            v2_coords_np = np.array(all_vertices[face_indices[i+1]], dtype=np.float64)
        except IndexError:
            # print(f"错误 (triangulate_face): 顶点索引 {face_indices[i]} 或 {face_indices[i+1]} 超出范围.")
            return [] 
        triangles_vertices_np.append((v0_coords_np, v1_coords_np, v2_coords_np))
    return triangles_vertices_np


def voxelize_raycast(
    all_vertices_list: list[list[float]],
    all_faces_indices: list[list[int]],
    grid_origin_tuple: tuple[float, float, float],
    voxel_size: float,
    grid_dimensions_tuple: tuple[int, int, int],
    use_bvh: bool = True, 
    max_tris_per_bvh_leaf: int = 8,
    bvh_verbose: bool = False
) -> list[dict[str, int]]:
    """
    使用射线投射法将模型体素化，可选BVH加速。
    """
    method_str = "BVH加速" if use_bvh else "无加速 (暴力遍历)"
    print(f"开始体素化过程 (射线投射法 - {method_str})...")
    print(f"  网格维度: {grid_dimensions_tuple}, 体素大小: {voxel_size}")
    print(f"  网格原点: ({grid_origin_tuple[0]:.3f}, {grid_origin_tuple[1]:.3f}, {grid_origin_tuple[2]:.3f})")


    active_voxels: list[dict[str, int]] = []
    grid_origin_np = np.array(grid_origin_tuple, dtype=np.float64)

    # 1. 三角化
    # print("  步骤1: 三角化模型的所有面...") # main.py 中已经有类似信息
    triangulation_start_time = time.time()
    model_triangles_np: list[tuple[np.ndarray, np.ndarray, np.ndarray]] = []
    for face_idx_list in all_faces_indices:
        triangles_from_face = triangulate_face(face_idx_list, all_vertices_list)
        if not triangles_from_face and len(face_idx_list) >=3 :
             # 这个警告级别较低，可以考虑是否保留或由main.py控制日志级别
             # print(f"提示 (voxelize_raycast): 面 {face_idx_list} (含{len(face_idx_list)}顶点) 三角化后为空。")
             pass
        model_triangles_np.extend(triangles_from_face)
    triangulation_end_time = time.time()
    # print(f"  三角化完成，共得到 {len(model_triangles_np)} 个三角形。耗时: {triangulation_end_time - triangulation_start_time:.4f} 秒。")

    if not model_triangles_np:
        print("警告 (voxelize_raycast): 模型中没有有效的三角形可以进行体素化。")
        return []

    bvh_root_node: BVHNode | None = None
    actual_use_bvh = use_bvh # 记录实际是否使用了BVH，因为构建可能失败
    if use_bvh:
        # print(f"  步骤1.5: 构建BVH树 (每个叶子节点最多 {max_tris_per_bvh_leaf} 个三角形)...")
        bvh_build_start_time = time.time()
        bvh_root_node = build_bvh(model_triangles_np, 
                                  max_tris_per_leaf=max_tris_per_bvh_leaf, 
                                  verbose=bvh_verbose)
        bvh_build_end_time = time.time()
        if bvh_root_node:
            print(f"  BVH树已构建。构建耗时: {bvh_build_end_time - bvh_build_start_time:.4f} 秒。")
        else:
            print("  警告 (voxelize_raycast): BVH树构建失败，将回退到无加速模式。")
            actual_use_bvh = False 
    
    # 射线方向 (固定)
    dx, dy, dz = 1.0, 0.1, 0.05 
    norm_factor = math.sqrt(dx*dx + dy*dy + dz*dz)
    if norm_factor < EPSILON: # 检查 norm_factor 是否接近0
        RAY_DIRECTION_NP = np.array([1.0,0.0,0.0], dtype=np.float64) 
        print("警告 (voxelize_raycast): 射线方向向量范数接近零，已重置为 [1,0,0]。")
    else: 
        RAY_DIRECTION_NP = np.array([dx/norm_factor, dy/norm_factor, dz/norm_factor], dtype=np.float64)
    
    inv_RAY_DIRECTION_NP = np.zeros_like(RAY_DIRECTION_NP)
    signs_RAY_DIRECTION_NP = np.zeros(3, dtype=int)

    for i in range(3): # 总是计算，因为无BVH时也可能用于未来优化
        if abs(RAY_DIRECTION_NP[i]) < EPSILON:
            inv_RAY_DIRECTION_NP[i] = np.inf if RAY_DIRECTION_NP[i] >= 0 else -np.inf
        else:
            inv_RAY_DIRECTION_NP[i] = 1.0 / RAY_DIRECTION_NP[i]
        signs_RAY_DIRECTION_NP[i] = 1 if RAY_DIRECTION_NP[i] >= 0 else 0
    
    # print(f"  步骤2: 遍历体素网格并执行射线投射 (射线方向: [{RAY_DIRECTION_NP[0]:.3f}, {RAY_DIRECTION_NP[1]:.3f}, {RAY_DIRECTION_NP[2]:.3f}])...")
    dim_x, dim_y, dim_z = grid_dimensions_tuple
    total_voxels_to_check = dim_x * dim_y * dim_z
    checked_voxels_count = 0
    # 进度条打印间隔调整：至少1%，最多每秒几次（如果计算快）
    # 这里简单地按数量间隔
    progress_interval = max(1, total_voxels_to_check // 200) # 0.5% 间隔
    if total_voxels_to_check < 100 : progress_interval = 1 # 小网格频繁更新
    
    last_progress_print_time = time.time()

    voxel_loop_start_time = time.time()
    for ix in range(dim_x):
        for iy in range(dim_y):
            for iz in range(dim_z):
                checked_voxels_count += 1
                voxel_center_np = grid_origin_np + \
                                  np.array([ix + 0.5, iy + 0.5, iz + 0.5], dtype=np.float64) * voxel_size
                ray_origin_np_current = voxel_center_np
                
                intersection_count = 0
                if actual_use_bvh and bvh_root_node:
                    all_t_values = traverse_bvh_and_get_intersections(
                        ray_origin_np_current, RAY_DIRECTION_NP,
                        inv_RAY_DIRECTION_NP, signs_RAY_DIRECTION_NP,
                        bvh_root_node
                    )
                    intersection_count = len(all_t_values)
                else: 
                    for triangle_verts_np in model_triangles_np:
                        t_val = ray_intersects_triangle(ray_origin_np_current, RAY_DIRECTION_NP, triangle_verts_np)
                        if t_val is not None:
                            intersection_count += 1
                
                if intersection_count % 2 == 1:
                    active_voxels.append({"x": ix, "y": iy, "z": iz})

                # 更新进度条逻辑
                current_time = time.time()
                if total_voxels_to_check > 0 and \
                   (checked_voxels_count == total_voxels_to_check or \
                    (checked_voxels_count % progress_interval == 0 and current_time - last_progress_print_time > 0.2)): # 每0.2秒或按间隔
                    progress_percent = (checked_voxels_count / total_voxels_to_check) * 100
                    print(f"    进度: {checked_voxels_count}/{total_voxels_to_check} ({progress_percent:.1f}%) 体素已检查...", end='\r', flush=True)
                    last_progress_print_time = current_time
        
        # if total_voxels_to_check > 0 and dim_x > 1 and dim_y > 1: # 避免在进度条最后一行后立即打印
        #     # 这个逐层打印可能与行内进度条冲突，暂时注释
        #     # print(f"  完成 X = {ix} / {dim_x-1} 层的体素检查...                                     ") 
        #     pass

    if total_voxels_to_check > 0: print("\r" + " " * 80 + "\r", end="") # 清除最后一行进度条
    voxel_loop_end_time = time.time()
    # print(f"  射线投射循环耗时: {voxel_loop_end_time - voxel_loop_start_time:.4f} 秒。")
    # print(f"体素化完成。共找到 {len(active_voxels)} 个激活体素。") # 这些信息移到main.py中打印总耗时
    return active_voxels

if __name__ == "__main__":
    print("--- 开始测试 voxelizer_core.py ---")
    
    # --- 测试 triangulate_face ---
    print("\n--- 测试 triangulate_face ---")
    mock_vertices_list_tri_test = [
        [1.0, 0.0, 0.0], [0.0, 1.0, 0.0], [0.0, 0.0, 1.0],
        [1.0, 1.0, 0.0], [2.0, 0.0, 0.0]
    ]
    face1_indices = [0, 1, 2] # 三角形
    triangles1 = triangulate_face(face1_indices, mock_vertices_list_tri_test)
    assert len(triangles1) == 1, f"三角化测试1失败: 期望1个三角,得到{len(triangles1)}"
    if triangles1 : assert isinstance(triangles1[0][0], np.ndarray), "三角化顶点应为NumPy数组"
    print(f"  从面 {face1_indices} 生成了 {len(triangles1)} 个三角形: 通过")

    face2_indices = [0,1,3,2] # 四边形
    triangles2 = triangulate_face(face2_indices, mock_vertices_list_tri_test)
    assert len(triangles2) == 2, f"三角化测试2失败: 期望2个三角,得到{len(triangles2)}"
    print(f"  从面 {face2_indices} 生成了 {len(triangles2)} 个三角形: 通过")
    print("--- triangulate_face 测试通过 ---")


    # --- 测试 voxelize_raycast (有/无BVH) ---
    print("\n--- 测试 voxelize_raycast (核心逻辑) ---")
    cube_vertices_list = [
        [0.0, 0.0, 0.0], [1.0, 0.0, 0.0], [1.0, 1.0, 0.0], [0.0, 1.0, 0.0],
        [0.0, 0.0, 1.0], [1.0, 0.0, 1.0], [1.0, 1.0, 1.0], [0.0, 1.0, 1.0]
    ]
    cube_faces_indices_list = [ # 6个四边形面
        [0, 3, 2, 1], [4, 5, 6, 7], [0, 1, 5, 4], 
        [1, 2, 6, 5], [2, 3, 7, 6], [3, 0, 4, 7]
    ]
    test_grid_origin_tuple = (0.0, 0.0, 0.0)

    test_configs = [
        {"name": "Cube_2x2x2_NoBVH", "voxel_size": 0.5, "grid_dims": (2,2,2), "use_bvh": False, "expected_voxels": 8},
        {"name": "Cube_2x2x2_BVH",   "voxel_size": 0.5, "grid_dims": (2,2,2), "use_bvh": True,  "expected_voxels": 8},
        {"name": "Cube_4x4x4_NoBVH", "voxel_size": 0.25,"grid_dims": (4,4,4), "use_bvh": False, "expected_voxels": 64},
        {"name": "Cube_4x4x4_BVH",   "voxel_size": 0.25,"grid_dims": (4,4,4), "use_bvh": True,  "expected_voxels": 64},
    ]
    
    overall_tests_passed = True
    for config in test_configs:
        print(f"\n--- 测试案例: {config['name']} ---")
        print(f"  预期网格维度: {config['grid_dims']}, 体素大小: {config['voxel_size']}, BVH: {config['use_bvh']}")
        print(f"  预期激活体素数量: {config['expected_voxels']}")
        
        test_start_time = time.time()
        active_voxels = voxelize_raycast(
            cube_vertices_list, cube_faces_indices_list,
            test_grid_origin_tuple, config['voxel_size'], config['grid_dims'],
            use_bvh=config['use_bvh'],
            max_tris_per_bvh_leaf=4, # BVH叶子节点大小适中
            bvh_verbose=False # 测试时通常不需BVH详细日志
        )
        test_end_time = time.time()
        print(f"  {config['name']} 体素化总耗时: {test_end_time - test_start_time:.4f} 秒。")
        print(f"  结果: 共 {len(active_voxels)} 个激活体素。")

        if len(active_voxels) == config['expected_voxels']:
            print(f"  测试 {config['name']} 通过！")
        else:
            print(f"  !!! 测试 {config['name']} 失败: 期望 {config['expected_voxels']}个体素, 得到 {len(active_voxels)} !!!")
            overall_tests_passed = False
            # 详细打印出哪些体素缺失或多余可能有助于调试
            # expected_set = set(...) # 需要生成预期的体素坐标集合
            # actual_set = set((v['x'], v['y'], v['z']) for v in active_voxels)
            # print(f"    多余的体素: {actual_set - expected_set}")
            # print(f"    缺失的体素: {expected_set - actual_set}")

    if overall_tests_passed:
        print("\n--- voxelize_raycast 所有核心逻辑测试通过！ ---")
    else:
        print("\n--- !!! voxelize_raycast 部分或所有核心逻辑测试失败 !!! ---")

    print("\n--- voxelizer_core.py 测试结束 ---")